#include <iostream>
#include <fstream>
#include <iomanip>
#include "laval.h"
#include <ctime>
#include <cstring>
#include <jsoncpp/json/json.h>
using namespace std;

/**
 * @brief find max value for flux or vars
 */
template <typename T>
double get_max(T first, T last)
{
    double _max = 0.0;
    for (; first != last; first++)
    {
        if (fabs(*first) >= _max)
            _max = fabs(*first);
        else
            _max = _max;
    }

    return _max;
}

void cfd_procs(void)
{

    string str;
    int num, iter, line = 2, maxstp;
    ifstream ctrl_file;

    double start = clock();
    double end;
    double u_max;
    double res_max;
    double cfl_;

    Json::Value obj;
    Json::Reader js_reader;

    ctrl_file.open("control.json", ios::in);
#if 0
    getline(ctrl_file, str);
    getline(ctrl_file, str);
    int id = str.rfind(':');
    num = stoi(str.substr(id + 1));
    maxstp = stoi(str.substr(id + 5));
    cfl_ = stod(str.substr(id + 11));
    ctrl_file.close();
#endif

    if (js_reader.parse(ctrl_file, obj)) //< g++ ***.cpp -ljsoncpp
    {
        num = obj["num"].asInt();
        maxstp = obj["iter"].asInt();
        cfl_ = obj["cfl"].asDouble();
    }
    ctrl_file.close();

    laval lav(0.1, 1.0, num);
    double Res[lav.ncells_];
    super_init(lav, lav.xc_, lav.r_, lav.p_, lav.e_, lav.u_, lav.m_, lav.q_);
    lav.cfl = cfl_;
    for (int n = 0; n < maxstp; n++)
    {
        lav.time_advance(laval::RK4);

        for (int i = 0; i < lav.ncells_; i++)
            Res[i] = lav.R_[i][0];

        res_max = get_max(Res, Res + lav.ncells_);
        end = clock();

        if (n % 4000 == 0)
            cout << "Iters" << '\t' << "Res_max(rho)" << '\t' << setw(10) << "Time(s)" << '\t'
                 << setw(9) << "dt(s)" << endl;
        if (n % 200 == 0)
            cout << setw(5) << n << '\t' << scientific << setprecision(5) << res_max << '\t'
                 << (end - start) / CLOCKS_PER_SEC << '\t' << setw(5) << lav.dt << endl;
    }

    lav.tecout();

    cout << endl;
    cout << " << All computation is finished ! >>" << endl;

    return;
}

int main()
{
    cfd_procs();
    return 0;
}
